/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.bff.engine.api.filter;

import com.inspur.edp.bef.bizentity.GspBusinessEntity;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.element.GspAssociation;
import com.inspur.edp.cef.designtime.api.entity.MappingInfo;
import com.inspur.edp.cef.spi.jsonser.base.StringUtils;
import com.inspur.edp.commonmodel.engine.api.common.CMEngineUtil;
import com.inspur.edp.das.commonmodel.IGspCommonElement;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.formserver.viewmodel.GspViewModel;
import com.inspur.edp.formserver.viewmodel.GspViewModelElement;
import com.inspur.edp.formserver.viewmodel.GspViewObject;
import com.inspur.edp.udt.designtime.api.entity.ComplexDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.SimpleDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.UnifiedDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.dbInfo.ColumnMapType;

import java.util.Map;
import java.util.Objects;

public class FilterConvertorUtil {
    public static void initFilterDic(String label, String returnValue, Map<String, String> filterDic) {
        filterDic.put(label, returnValue);
        if (!label.equals(StringUtils.toCamelCase(label))) {
            filterDic.put(StringUtils.toCamelCase(label), returnValue);
        }

        String labelToCamel = toCamel(label);
        if (!filterDic.containsKey(labelToCamel)) {
            filterDic.put(labelToCamel, returnValue);
        }
    }

    public static void initFilterDic(GspBusinessEntity be, GspViewModel vo, Map<String, String> filterDic) {
        if (vo.getIsVirtual() || vo.getMainObject().getIsVirtual())
            return;
        for (IGspCommonElement voElement : vo.getMainObject().getAllElementList(false)) {
            if (voElement.getIsVirtual()) {
                continue;
            }
            if (voElement.getIsUdt()) {
                initUdtElement((IGspCommonField)voElement, voElement.getLabelID(), "", be, vo, filterDic);
                continue;
            }
            if (voElement.getHasAssociation()) {
                initAssociationElement((IGspCommonField)voElement, voElement.getLabelID(), "", be, vo, filterDic);
            }
        }
    }

    /**
     * 初始化UDT字段
     * @param voElement
     * @param parentLabel
     * @param returnValue
     * @param be
     * @param vo
     * @param filterDic
     */
    public static void initUdtElement(IGspCommonField voElement, String parentLabel, String returnValue, GspBusinessEntity be, GspViewModel vo, Map<String, String> filterDic) {
        UnifiedDataTypeDef udt = (UnifiedDataTypeDef) CMEngineUtil.getMetadataContent(voElement.getUdtID());
        if (udt == null) {
            throw new RuntimeException(String.format("未找到ID为：%1$s，名称为：%2$s的udt元数据，请确认该元数据是否已经部署入库。", new Object[] { voElement.getUdtID(), voElement.getUdtName() }));
        }
        if (udt != null && udt instanceof SimpleDataTypeDef) {
            initSimpleUdtElement(voElement, (udt instanceof SimpleDataTypeDef) ? (SimpleDataTypeDef)udt : null, parentLabel, returnValue, be, vo, filterDic);

        }
        else {

            initComplexUdtElement(voElement, (udt instanceof ComplexDataTypeDef) ? (ComplexDataTypeDef)udt : null, be, vo, filterDic);
        }
    }



    public static void initSimpleUdtElement(IGspCommonField voElement, SimpleDataTypeDef udt, String parentLabel, String returnValue, GspBusinessEntity be, GspViewModel vo, Map<String, String> filterDic) {
        String udtLabel = parentLabel + "." + udt.getCode();
        String udtLabelTemp = udtLabel + "." + udt.getCode();
        initFilterDic(udtLabelTemp, parentLabel, filterDic);
        IGspCommonField beElement = getBeElement((voElement instanceof GspViewModelElement) ? (GspViewModelElement)voElement : null, be);

        if (beElement == null) {
            throw new RuntimeException("没有找到字段" + voElement.getLabelID() + "的映射字段");
        }

        String value = isNullOrEmpty(returnValue) ? beElement.getLabelID() : returnValue;

        initFilterDic(udtLabel, value, filterDic);
        initFilterDic(voElement.getLabelID(), value, filterDic);

        if (voElement.getHasAssociation()) {
            GspAssociation asso = (GspAssociation)udt.getChildAssociations().get(0);
            initUdtAssociation(voElement, udtLabel, returnValue, asso, be, vo, filterDic);
        }
    }
    public static void initComplexUdtElement(IGspCommonField voElement, ComplexDataTypeDef udt, GspBusinessEntity be, GspViewModel vo, Map<String, String> filterDic) {
        if (udt.getDbInfo().getMappingType() == ColumnMapType.SingleColumn) {
            return;
        }
        IGspCommonField beElement = getBeElement((voElement instanceof GspViewModelElement) ? (GspViewModelElement)voElement : null, be);

        if (beElement == null) {
            throw new RuntimeException("没有找到字段" + voElement.getLabelID() + "的映射字段");
        }

        for (MappingInfo mapping : beElement.getMappingRelation()) {
            String beChildEleId = mapping.getKeyInfo();
            String udtEleId = mapping.getValueInfo();
            IGspCommonField beChildElement = getBeChildElement(beElement, beChildEleId);

            IGspCommonField udtElement = udt.findElement(udtEleId);
            if (beChildElement == null || udtElement == null) {
                throw new RuntimeException("Vo" + vo
                        .getMainObject().getBelongModel().getCode() + "编译失败，多值UDT" + udt
                        .getCode() + "数据库映射有异常");
            }
            buildUdtElementSection(voElement, udtElement, beChildElement, udt, filterDic);
        }
    }



    public static void buildUdtElementSection(IGspCommonField voElement, IGspCommonField udtElement, IGspCommonField beElement, ComplexDataTypeDef udt, Map<String, String> filterDic) {
        String udtLabel = voElement.getLabelID() + "." + udtElement.getLabelID();
        initFilterDic(udtLabel, beElement.getLabelID(), filterDic);
        initFilterDic(beElement.getLabelID(), beElement.getLabelID(), filterDic);
    }



    public static IGspCommonField getBeChildElement(IGspCommonField beElement, String childId) {
        for (IGspCommonField beChildElement : beElement.getChildElements()) {
            if (childId.equals(beChildElement.getID())) {
                return beChildElement;
            }
        }
        return null;
    }


    /**
     * 初始化关联udt字段
     * @param voElement
     * @param parentLabel
     * @param returnValue
     * @param udtAsso
     * @param be
     * @param vo
     * @param filterDic
     */
    public static void initUdtAssociation(IGspCommonField voElement, String parentLabel, String returnValue, GspAssociation udtAsso, GspBusinessEntity be, GspViewModel vo, Map<String, String> filterDic) {
        GspAssociation asso = (GspAssociation)voElement.getChildAssociations().get(0);
        for (IGspCommonField refElement : asso.getRefElementCollection()) {
            IGspCommonField beElement = getBeElement((refElement instanceof GspViewModelElement) ? (GspViewModelElement)refElement : null, be);

            if (beElement == null) {
                throw new RuntimeException(((GspViewObject)voElement.getBelongObject()).getBelongModel().getCode() + "中，关联字段" + voElement
                        .getLabelID() + "的关联带出字段" + refElement.getLabelID() + "对应的be带出字段不存在");
            }
            IGspCommonField udtRefElement = getUdtRefElement(refElement, udtAsso);
            String childValue = isNullOrEmpty(returnValue) ? beElement.getLabelID() : returnValue;
            String childLabel = isNullOrEmpty(parentLabel) ? refElement.getLabelID() : parentLabel;
            if (udtRefElement != null) {
                childLabel = childLabel + "." + udtRefElement.getLabelID();
            } else {
                childLabel = childLabel + "." + refElement.getLabelID();
            }
            if (refElement.getIsUdt()) {
                initUdtElement(refElement, childLabel, childValue, be, vo, filterDic); continue;
            }
            initFilterDic(childLabel, childValue, filterDic);
        }
    }





    public static IGspCommonField getUdtRefElement(IGspCommonField refElement, GspAssociation udtAsso) {
        for (IGspCommonField udtRefElement : udtAsso.getRefElementCollection()) {
            if (udtRefElement.getRefElementId().equals(refElement.getRefElementId())) {
                return udtRefElement;
            }
        }
        return null;
    }


    public static void initAssociationElement(IGspCommonField voElement, String parentLabel, String returnValue, GspBusinessEntity be, GspViewModel vo, Map<String, String> filterDic) {
        GspAssociation asso = (GspAssociation)voElement.getChildAssociations().get(0);
        initFilterDic(parentLabel + "." + parentLabel, parentLabel, filterDic);
        for (IGspCommonField refElement : asso.getRefElementCollection()) {
            IGspCommonField beElement = getBeElement((refElement instanceof GspViewModelElement) ? (GspViewModelElement)refElement : null, be);


            if (beElement == null)
                throw new RuntimeException("字段" + refElement.getLabelID() + "对应的be字段没有获取到" + ((GspViewModelElement)refElement).getMapping().getTargetElementId());
            String childValue = isNullOrEmpty(returnValue) ? beElement.getLabelID() : returnValue;
            String childLabel = isNullOrEmpty(parentLabel) ? refElement.getLabelID() : parentLabel;

            childLabel = childLabel + "." + refElement.getLabelID();
            if (refElement.getIsUdt()) {
                initUdtElement(refElement, childLabel, childValue, be, vo, filterDic); continue;
            }
            initFilterDic(childLabel, childValue, filterDic);
        }
    }



    public static boolean isNullOrEmpty(String value) {
        return (value == null || value.equals(""));
    }


    public static IGspCommonField getBeElement(GspViewModelElement voElement, GspBusinessEntity be) {
        String objId = voElement.getMapping().getTargetObjectId();
        if (objId == null || "".equals(objId))
            throw new RuntimeException("字段" + voElement.getCode() + "上没有记录映射对象Id，请打开vo设计器重新添加字段");
        if (objId.equals(be.getMainObject().getID())) {
            return getBeElemet(voElement, (IGspCommonObject)be.getMainObject());
        }
        GspBusinessEntity elementBelongBe = null;
        String metadataId = voElement.getMapping().getTargetMetadataId();
        if (metadataId.equals(be.getID())) {
            elementBelongBe = be;
        } else {
            elementBelongBe = (GspBusinessEntity)CMEngineUtil.getMetadataContent(metadataId);
            Objects.requireNonNull(elementBelongBe, "metadata:" + voElement.getMapping().getTargetMetadataId());
            Objects.requireNonNull(elementBelongBe, "elementBelongBe");
        }

        IGspCommonObject beObj = elementBelongBe.findObjectById(objId);
        if (beObj == null)
            throw new RuntimeException("be元数据" + be.getCode() + "上没有找到对象" + objId + "，对应vo对象为" + voElement.getBelongObject().getCode());
        return getBeElemet(voElement, beObj);
    }

    public static IGspCommonField getBeElemet(GspViewModelElement voElement, IGspCommonObject beObj) {
        if (!voElement.getIsRefElement()) {
            return (IGspCommonField)beObj.findElement(voElement.getMapping().getTargetElementId());
        }
        for (IGspCommonElement beEle : beObj.getAllElementList(true)) {
            if (beEle.getID().equals(voElement.getMapping().getTargetElementId())) {
                return (IGspCommonField)beEle;
            }
        }

        return null;
    }
    public static String toCamel(String propName) {
        if (!propName.contains("."))
            return StringUtils.toCamelCase(propName);
        String[] strArray = propName.split("\\.");
        int length = strArray.length;
        String propLabelName = "";
        for (int i = 0; i < length; i++) {
            propLabelName = propLabelName + StringUtils.toCamelCase(strArray[i]);
            if (i >= 0 && i < length - 1) {
                propLabelName = propLabelName + ".";
            }
        }

        return propLabelName;
    }
}
